package stackexchange;

import java.util.Calendar;
import java.util.Vector;

import stackexchange.posts.Answer;
import stackexchange.posts.Comment;
import stackexchange.posts.Question;
import parser.XmlParser;
import static stackexchange.Constants.CURRENT_DATE;

public class User {
	private int id;
	private String name;
	private int reputation;
	private Calendar creationDate;
	private Calendar lastAccessDate;
	private int profileViews;
	private int upVotes;
	private int downVotes;
	private int accountId;
	private int nOfEdits = 0;
	private String aboutMe;
	private Vector<Question> allQuestions = new Vector<Question>();
	private Vector<Answer> allAnswers = new Vector<Answer>();
	private Vector<Comment> allComments = new Vector<Comment>();
	private Vector<Badge> allBadges = new Vector<Badge>();
	private double expertiseScore = -1;
	int orig;

	public double getExpertiseScore() {
		return expertiseScore;
	}

	public void addComment(Comment c) {
		allComments.add(c);
	}

	public int getNofComments() {
		return allComments.size();
	}

	public User(int id, String name, int accountId, int reputation,
			Calendar creationDate, Calendar lastAccessDate, int profileViews,
			int upVotes, int downVotes) {
		orig = reputation;
		this.id = id;
		this.name = name;
		this.accountId = accountId;
		this.reputation = reputation;
		this.creationDate = creationDate;
		this.lastAccessDate = lastAccessDate;
		this.profileViews = profileViews;
		this.upVotes = upVotes;
		this.downVotes = downVotes;
	}

	public void addQuestion(Question post) {
		allQuestions.add(post);
	}

	public void addAnswer(Answer post) {
		allAnswers.add(post);
	}

	public void setExpertiseScore(double score) {
		this.expertiseScore = score;
	}

	public Vector<Question> getUsersQuestions() {
		return allQuestions;
	}

	public Vector<Answer> getUsersAnswers() {
		return allAnswers;
	}

	public int getId() {
		return id;
	}

	public int getReputation() {
		return reputation;
	}

	public Calendar getCreationDate() {
		return creationDate;
	}

	public Calendar getLastAccessDate() {
		return lastAccessDate;
	}

	public int getProfileViews() {
		return profileViews;
	}

	public int getUpVotes() {
		return upVotes;
	}

	public int getDownVotes() {
		return downVotes;
	}

	public int getAverageQuestionLength() {
		if (allQuestions.size() == 0) {
			return 0;
		}
		return getTotalQuestionLength() / allQuestions.size();
	}

	public int getTotalQuestionLength() {
		int sum = 0;
		for (int i = 0; i < allQuestions.size(); i++) {
			sum = sum + allQuestions.get(i).getBody().length();
		}
		return sum;
	}

	public int getAverageAnswerLength() {
		if (allAnswers.size() == 0) {
			return 0;
		}
		return getTotalAnswerLength() / allAnswers.size();
	}

	public int getTotalAnswerLength() {
		int sum = 0;
		for (int i = 0; i < allAnswers.size(); i++) {
			sum = sum + allAnswers.get(i).getBody().length();
		}
		return sum;
	}

	public void setReputation() {
		this.reputation = calculateReputation(allQuestions, allAnswers);
	}

	public Vector<Question> getAllQuestions() {
		return allQuestions;
	}

	private int calculateReputation(Vector<Question> allQuestions,
			Vector<Answer> allAnswers) {
		int reputation = 1;
		for (int i = 0; i < allQuestions.size(); i++) {
			reputation = reputation + allQuestions.get(i).getScore() * 5;
		}
		for (int i = 0; i < allAnswers.size(); i++) {
			reputation = reputation + allAnswers.get(i).getScore() * 10;
			if (allAnswers.get(i).isAnAcceptedAnswer()) {
				reputation = reputation + 15;
			}
		}
		return reputation;
	}

	public Vector<Question> getAllQuestionsWithin(int days) {
		Vector<Question> questions = new Vector<Question>();
		for (int i = 0; i < allQuestions.size(); i++) {
			if (getDifference(creationDate, allQuestions.get(i)
					.getCreationDate()) <= days) {
				questions.add(allQuestions.get(i));
			}
		}
		return questions;
	}

	public Vector<Answer> getAllAnswersWithin(int days) {
		Vector<Answer> answers = new Vector<Answer>();
		for (int i = 0; i < allAnswers.size(); i++) {
			if (getDifference(creationDate, allAnswers.get(i).getCreationDate()) <= days) {
				answers.add(allAnswers.get(i));
			}
		}
		return answers;
	}

	public int getReputationWithin1Mounth() {
		return calculateReputation(getAllQuestionsWithin(30),
				getAllAnswersWithin(30));
	}

	public int getReputationWithin3Mounths() {
		return calculateReputation(getAllQuestionsWithin(90),
				getAllAnswersWithin(90));
	}

	public int getReputationWithin6Mounths() {
		return calculateReputation(getAllQuestionsWithin(180),
				getAllAnswersWithin(180));
	}

	public int getReputationWithin1Year() {
		return calculateReputation(getAllQuestionsWithin(365),
				getAllAnswersWithin(365));
	}

	public int getReputationWithin18Mounths() {
		return calculateReputation(getAllQuestionsWithin(540),
				getAllAnswersWithin(540));
	}

	public int getReputationWithin2Years() {
		return calculateReputation(getAllQuestionsWithin(730),
				getAllAnswersWithin(730));
	}

	public int getReputationWithin3Year() {
		return calculateReputation(getAllQuestionsWithin(1095),
				getAllAnswersWithin(1095));
	}

	public int isUserSince() {
		return getDifference(creationDate, CURRENT_DATE);
	}

	public int completeDays(int from, int to) {
		if (from < to) {
			return to - from;
		} else if (from == to) {
			return 0;
		} else {
			return -((30 + to) - from);
		}
	}

	public int completeMonths(int from, int to) {
		if (from < to) {
			return 30 * (to - from);
		} else if (from == to) {
			return 0;
		} else {
			return -30 * ((12 + to) - from);
		}
	}

	/**
	 * 
	 * @param a
	 * @return difference as #days with current date
	 */
	public int getDifference(Calendar a, Calendar b) {
		int totalDays = 0;
		int yearA = a.get(Calendar.YEAR);
		int monthA = a.get(Calendar.MONTH);
		int dayA = a.get(Calendar.DAY_OF_MONTH);
		int yearC = b.get(Calendar.YEAR);
		int monthC = b.get(Calendar.MONTH);
		int dayC = b.get(Calendar.DAY_OF_MONTH);
		totalDays = completeDays(dayA, dayC);
		// System.out.println("-------"+dayC);
		// System.out.println(monthC);
		// System.out.println(yearC);
		// System.out.println("->> " + totalDays);
		if (totalDays < 0) {
			totalDays = totalDays * (-1);
			monthA++;
			if (monthA == 13) {
				yearA++;
				monthA = 0;
			}
		}
		int daysFromMonth = completeMonths(monthA, monthC);
		// System.out.println("->> " + daysFromMonth);
		if (daysFromMonth < 0) {
			daysFromMonth = daysFromMonth * (-1);
			yearA++;
		}
		totalDays = totalDays + daysFromMonth + completeYears(yearA, yearC);
		return totalDays;
	}

	public int completeYears(int from, int to) {
		if (from < to) {
			return 365 * (to - from);
		}
		return 0;
	}

	public int getAccountId() {
		return accountId;
	}

	public String getName() {
		return name;
	}

	public int getNofQuestions() {
		return allQuestions.size();
	}

	public int getNofAnswers() {
		return allAnswers.size();
	}

	private String fillGap(String name, int desiredLength) {
		int gap = desiredLength - name.length();
		String result = " ";
		for (int i = 0; i < gap; i++) {
			result = result.concat(" ");
		}
		return result;
	}

	private String fillGap(int textLength, int desiredLength) {
		int gap = desiredLength - String.valueOf(textLength).length();
		String result = " ";
		for (int i = 0; i < gap; i++) {
			result = result.concat(" ");
		}
		return result;
	}

	public String toString() {
		return name + " - " + fillGap(name, 20) + reputation
				+ fillGap(reputation, 5) + " - " + orig + fillGap(orig, 5)
				+ " - UpVotes: " + upVotes + fillGap(upVotes, 5)
				+ " - DownVotes: " + downVotes + fillGap(downVotes, 5)
				+ " - Views: " + profileViews + fillGap(profileViews, 5)
				+ " - #Questions: " + allQuestions.size()
				+ fillGap(allQuestions.size(), 5) + " - #Answers: "
				+ allAnswers.size() + fillGap(profileViews, 5) + " Id: "
				+ getId() + printExpScore();
	}

	private String printExpScore() {
		if (expertiseScore == -1) {
			return "";
		}
		return fillGap(getId(), 5) + " Exp Score: " + expertiseScore;
	}

	public Vector<Badge> getBadges() {
		return allBadges;
	}

	public int getNofBadges() {
		return allBadges.size();
	}

	public void addBadge(Badge badge) {
		allBadges.add(badge);
	}

	public void increaseNofEdits() {
		nOfEdits = nOfEdits + 1;
	}

	public int getNofEdits() {
		return nOfEdits;
	}
}
